
/* http://code.google.com/p/yaml-cpp/wiki/HowToParseADocument */
#include "YamlParser.h"
#include <ctype.h>
#include <stdlib.h>


inline bool isInteger(const std::string & s) {
    if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) 
        return false ;

    char * p ;
    strtol(s.c_str(), &p, 10) ;

    return (*p == 0) ;
}

std::string validate_or_default_node_string(const YAML::Node& node,
                                            std::string tag,
                                            std::string parent,
                                            std::string default_value ) {

    const YAML::Node *parsed;
    std::string s;
    std::string msg_out;
    std::string ret_value;

    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue(tag)) ) {
            if ( (*parsed).Type() == YAML::NodeType::Scalar ){
                *parsed >> s;
                msg_out = "YAML::OK! '" + tag + ": " + s + "' en "+ parent;
                LOGUEAR( msg_out, 1 );
                *parsed >> ret_value;
            } else {
                msg_out = "YAML::WARNING! clave: '" + tag + "' en "+ parent +" es de un tipo incorrecto";
                LOGUEAR( msg_out, 2 );
                ret_value = default_value;
            }
        } else {
            msg_out = "YAML::WARNING! clave: '" + tag + "' en "+ parent +" no existe";
            LOGUEAR( msg_out, 2 );
            ret_value = default_value;
        }
    } else {
        msg_out = "YAML::WARNING! clave: '" + tag + "' en "+ parent +" no existe";
        LOGUEAR( msg_out, 2 );
        ret_value = default_value;
    }

    //log( msg_out, 0 );
    return ret_value;
}

int validate_or_default_node_int( const YAML::Node& node,
                                  std::string tag,
                                  std::string parent,
                                  int default_value ) {

    const YAML::Node *parsed;
    std::string s;
    std::string msg_out;
    int ret_value;

    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue(tag)) ) {
            if ( (*parsed).Type() == YAML::NodeType::Scalar ){
                *parsed >> s;
                if ( isInteger( s ) ) {
                    msg_out = "YAML::OK! '" + tag + ": " + s + "' en "+ parent;
                    LOGUEAR( msg_out, 1 );
                    *parsed >> ret_value;
                    if (ret_value < 0)
                    	ret_value*=-1;
                } else {
                    msg_out = "YAML::WARNING! clave: '" + tag + "' en "+ parent +" no es de tipo numerico";
                    LOGUEAR( msg_out, 2 );
                    ret_value = default_value;
                }
            } else {
                msg_out = "YAML::WARNING! clave: '" + tag + "' en "+ parent +" es de un tipo incorrecto";
                LOGUEAR( msg_out, 2 );
                ret_value = default_value;
            }
        } else {
            msg_out = "YAML::WARNING! clave: '" + tag + "' en "+ parent +" no existe";
            LOGUEAR( msg_out, 2 );
            ret_value = default_value;
        }
    } else {
        msg_out = "YAML::WARNING! clave: '" + tag + "' en "+ parent +" no existe";
        LOGUEAR( msg_out, 2 );
        ret_value = default_value;
    }

    return ret_value;
}

void operator >> (const YAML::Node& node, Pantalla_y& pantalla) {
    pantalla.alto  = validate_or_default_node_int( node, "alto", "pantalla", 550 );
    pantalla.alto-=25;
    pantalla.ancho = validate_or_default_node_int( node, "ancho", "pantalla", 800 );
}

void operator >> (const YAML::Node& node, Conexion_y& conexion) {
    conexion.host = validate_or_default_node_string( node, "host", "conexion", "localhost" );
    conexion.port = validate_or_default_node_int( node, "port", "conexion", 51779 );
}

void operator >> (const YAML::Node& node, Parametros& parametros) {
    parametros.vel_personaje = validate_or_default_node_int( node, "vel_personaje", "parametros", 7 );
    parametros.margen_scroll = validate_or_default_node_int( node, "margen_scroll", "parametros", 200 );
}

void operator >> (const YAML::Node& node, Personaje_n& personaje) {
    personaje.tipo = validate_or_default_node_string( node, "tipo", "personaje", "personaje_default" );
    personaje.x = validate_or_default_node_int( node, "x", "personaje[ " + personaje.tipo + " ]", 300 );
    personaje.y = validate_or_default_node_int( node, "y", "personaje[ " + personaje.tipo + " ]", 500 );
    personaje.orientacion = validate_or_default_node_string( 
                                                            node,
                                                            "orientacion",
                                                            "personaje[ " + personaje.tipo + " ]",
                                                            "derecha" 
                                                            );
}

void operator >> (const YAML::Node& node, Plataforma_y& plataforma) {

    plataforma.imagen  = validate_or_default_node_string( node, "imagen", "plataforma", "plataforma_metal" );
    plataforma.x       = validate_or_default_node_int( node, "x",      "plataforma", 300 );
    plataforma.y       = validate_or_default_node_int( node, "y",      "plataforma", 300 );
    plataforma.ancho   = validate_or_default_node_int( node, "ancho",  "plataforma", 32  );
    plataforma.alto    = validate_or_default_node_int( node, "alto",   "plataforma", 32  );
    plataforma.angulo  = validate_or_default_node_int( node, "angulo", "plataforma", 0   );

}

void operator >> (const YAML::Node& node, Escalera_y& escalera) {

    escalera.imagen  = validate_or_default_node_string( node, "imagen",  "escalera", "escalera_metal" );
    escalera.x       = validate_or_default_node_int( node,    "x",       "escalera", 300    );
    escalera.y       = validate_or_default_node_int( node,    "y",       "escalera", 300    );
    escalera.ancho   = validate_or_default_node_int( node,    "ancho",   "escalera", 32     );
    escalera.alto    = validate_or_default_node_int( node,    "alto",    "escalera", 32     );

}

void operator >> (const YAML::Node& node, std::vector <Escalera_y>& escaleras) {
    for(unsigned i=0;i<node.size();i++) {
        Escalera_y escalera;
        node[i] >> escalera;
        escaleras.push_back( escalera );
    }
}

void operator >> (const YAML::Node& node, std::vector <Plataforma_y>& plataformas) {
    for(unsigned i=0;i<node.size();i++) {
        Plataforma_y plataforma;
        node[i] >> plataforma;
        plataformas.push_back( plataforma );
    }
}

void operator >> (const YAML::Node& node, std::vector <Personaje_n>& personajes) {
    for(unsigned i=0;i<node.size();i++) {
        Personaje_n personaje;
        node[i] >> personaje;
        personajes.push_back( personaje );
    }
}

void operator >> (const YAML::Node& node, Obstaculo_n& obstaculo) {
    obstaculo.tipo = validate_or_default_node_string( node, "tipo", "obstaculo", "CajaInterrogacion" );
    obstaculo.x = validate_or_default_node_int( node, "x", "obstaculo[ " + obstaculo.tipo + " ]", 300 );
    obstaculo.y = validate_or_default_node_int( node, "y", "obstaculo[ " + obstaculo.tipo + " ]", 500 );
    obstaculo.orientacion = validate_or_default_node_string( 
                                                            node,
                                                            "orientacion",
                                                            "obstaculo[ " + obstaculo.tipo + " ]",
                                                            "derecha" 
                                                            );
}

void operator >> (const YAML::Node& node, std::vector <Obstaculo_n>& obstaculos) {
    for(unsigned i=0;i<node.size();i++) {
        Obstaculo_n obstaculo;
        node[i] >> obstaculo;
        obstaculos.push_back( obstaculo );
    }
}

void operator >> (const YAML::Node& node, Nivel_y& nivel) {
    nivel.ancho = validate_or_default_node_int( node, "ancho", "nivel", 6784 );
    nivel.alto  = validate_or_default_node_int( node, "alto" , "nivel", 446 );
    nivel.gravedad  = validate_or_default_node_int( node, "gravedad" , "nivel", 10 );
    nivel.piso  = validate_or_default_node_int( node, "piso" , "nivel", 380 );
    nivel.fondo = validate_or_default_node_string( node, "fondo", "nivel", "world1.png" );
    nivel.sonido = validate_or_default_node_string( node, "sonido", "nivel", "" );

    const YAML::Node *parsed;

    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("plataformas")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Sequence ){
                *parsed >> nivel.plataformas;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'plataformas' en nivel no es del tipo correcto" , 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'plataformas' en nivel no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'plataformas' en nivel no existe", 2 );
    }

    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("escaleras")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Sequence ){
                *parsed >> nivel.escaleras;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'escaleras' en nivel no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'escaleras' en nivel no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'escaleras' en nivel no existe", 2 );
    }

    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("personajes")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Sequence ){
                *parsed >> nivel.personajes;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'personajes' en nivel no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'personajes' en nivel no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'personajes' en nivel no existe", 2 );
    }

    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("obstaculos")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Sequence ){
                *parsed >> nivel.obstaculos;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'obstaculos' en nivel no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'obstaculos' en nivel no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'obstaculos' en nivel no existe", 2 );
    }

}

/*void operator >> (const YAML::Node& node, std::vector <Textura>& texturas) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        Textura textura;
        it.first()  >> textura.nombre;
        it.second() >> textura.archivo;
        texturas.push_back( textura );
    }
}
*/

/*
void operator >> (const YAML::Node& node, std::vector <Sonido_y>& sonidos) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        Sonido_y sonido;
        it.first()  >> sonido.nombre;
        it.second() >> sonido.archivo;
        sonidos.push_back( sonido );
    }
}
*/

void operator >> (const YAML::Node& node, std::vector <Template_y>& templates) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        Template_y templatey;
        it.first()  >> templatey.nombre;
        it.second() >> templatey.archivo;
        templates.push_back( templatey );
    }
}

/*
void operator >> (const YAML::Node& node, std::vector <Imagen>& imagenes ) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        Imagen imagen;
        it.first()  >> imagen.nombre;
        it.second() >> imagen.archivo;
        imagenes.push_back( imagen );
    }
}
*/
void operator >> (const YAML::Node& node, Animacion_y& animacion) {
    animacion.periodo  = validate_or_default_node_int( node, "periodo" , "animacion", 5000 );
    animacion.cuadros  = validate_or_default_node_int( node, "cuadros" , "animacion", 15 );
    animacion.archivo  = validate_or_default_node_string( node, "sprites", "animacion", "default_sprite.png" );
}

void operator >> (const YAML::Node& node, std::vector <Animacion_y>& animaciones) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        Animacion_y animacion;
        it.first()  >> animacion.descripcion;
        it.second() >> animacion;

        animaciones.push_back( animacion );
    }
}

void operator >> (const YAML::Node& node, std::vector <Sonido_p>& sonidos) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        Sonido_p sonido;
        it.first()  >> sonido.accion;
        it.second() >> sonido.ruta;

        sonidos.push_back( sonido );
    }
}

void operator >> (const YAML::Node& node, TipoPersonaje_y& tipoPersonaje) {
    const YAML::Node *parsed;
    tipoPersonaje.ancho  = validate_or_default_node_int( node, "ancho", "tipoPersonaje", 60 );
    tipoPersonaje.alto   = validate_or_default_node_int( node, "alto" , "tipoPersonaje", 90 );
    tipoPersonaje.velocidad   = validate_or_default_node_int( node, "velocidad" , "tipoPersonaje", 50 );
    tipoPersonaje.salto  = validate_or_default_node_int( node, "salto", "tipoPersonaje", 150 );
    tipoPersonaje.velocidad  = validate_or_default_node_int( node, "velocidad", "tipoPersonaje", 200 );
    tipoPersonaje.velocidady = validate_or_default_node_int( node, "velocidady", "tipoPersonaje", 100 );
    tipoPersonaje.margen_scroll = validate_or_default_node_int( node, "margen_scroll", "tipoPersonaje", 200 );

    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("sonidos")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> tipoPersonaje.sonidos;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'sonidos' en tipoPersonaje no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'sonidos' en tipoPersonaje no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'sonidos' en tipoPersonaje no existe", 2 );
    }
    
    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("animaciones")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> tipoPersonaje.animaciones;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoPersonaje no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoPersonaje no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoPersonaje no existe", 2 );
    }

}

void operator >> (const YAML::Node& node, std::vector <TipoPersonaje_y>& tiposPersonaje) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        TipoPersonaje_y tipoPersonaje;
        it.first()  >> tipoPersonaje.tipo;
        it.second() >> tipoPersonaje;
        tiposPersonaje.push_back( tipoPersonaje );
    }
}

void operator >> (const YAML::Node& node, TipoBonus_y& tipoBonus) {
    const YAML::Node *parsed;
    tipoBonus.ancho  = validate_or_default_node_int( node, "ancho", "tipoBonus", 40 );
    tipoBonus.alto   = validate_or_default_node_int( node, "alto" , "tipoBonus", 40 );
    tipoBonus.velocidad   = validate_or_default_node_int( node, "velocidad" , "tipoBonus", 200 );
    tipoBonus.salto  = validate_or_default_node_int( node, "salto", "tipoBonus", 0 );
    tipoBonus.velocidad  = validate_or_default_node_int( node, "velocidad", "tipoBonus", 0 );
    tipoBonus.sonido = validate_or_default_node_string( node, "sonido", "tipoBonus", "" );
    
    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("animaciones")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> tipoBonus.animaciones;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoBonus no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoBonus no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoBonus no existe", 2 );
    }
}

void operator >> (const YAML::Node& node, std::vector <TipoBonus_y>& tiposBonus) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        TipoBonus_y tipoBonus;
        it.first()  >> tipoBonus.tipo;
        it.second() >> tipoBonus;
        tiposBonus.push_back( tipoBonus );
    }
}

void operator >> (const YAML::Node& node, TipoEnemigo_y& tipoEnemigo) {
    const YAML::Node *parsed;
    tipoEnemigo.ancho  = validate_or_default_node_int( node, "ancho", "tipoEnemigo", 40 );
    tipoEnemigo.alto   = validate_or_default_node_int( node, "alto" , "tipoEnemigo", 40 );
    tipoEnemigo.velocidad   = validate_or_default_node_int( node, "velocidad" , "tipoEnemigo", 200 );
    tipoEnemigo.salto  = validate_or_default_node_int( node, "salto", "tipoEnemigo", 0 );
    tipoEnemigo.velocidad  = validate_or_default_node_int( node, "velocidad", "tipoEnemigo", 0 );
    tipoEnemigo.velocidady = validate_or_default_node_int( node, "velocidady", "tipoEnemigo", 0 );
    
    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("animaciones")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> tipoEnemigo.animaciones;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoBonus no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoBonus no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoBonus no existe", 2 );
    }
}

void operator >> (const YAML::Node& node, std::vector <TipoEnemigo_y>& tiposEnemigo) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        TipoEnemigo_y tipoEnemigo;
        it.first()  >> tipoEnemigo.tipo;
        it.second() >> tipoEnemigo;
        tiposEnemigo.push_back( tipoEnemigo );
    }
}

void operator >> (const YAML::Node& node, TipoObstaculo_y& tipoObstaculo) {
    const YAML::Node *parsed;
    tipoObstaculo.ancho  = validate_or_default_node_int( node, "ancho", "tipoObstaculo", 40 );
    tipoObstaculo.alto   = validate_or_default_node_int( node, "alto" , "tipoObstaculo", 40 );
    
    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("animaciones")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> tipoObstaculo.animaciones;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoObstaculo no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoObstaculo no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoObstaculo no existe", 2 );
    }
}

void operator >> (const YAML::Node& node, std::vector <TipoObstaculo_y>& tiposObstaculo) {
    for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        TipoObstaculo_y tipoObstaculo;
        it.first()  >> tipoObstaculo.tipo;
        it.second() >> tipoObstaculo;
        tiposObstaculo.push_back( tipoObstaculo );
    }
}

void operator >> (const YAML::Node& node, std::vector <Nivel_y>& niveles) {
	for(YAML::Iterator it=node.begin();it!=node.end();++it) {
        Nivel_y nivel;
        it.first()  >> nivel.nombre;
        it.second() >> nivel;
        niveles.push_back( nivel );
    }
}

void operator >> (const YAML::Node& node, TipoPrincesa_y& tipoPrincesa) {
    const YAML::Node *parsed;
    tipoPrincesa.ancho  = validate_or_default_node_int( node, "ancho", "tipoPrincesa", 40 );
    tipoPrincesa.alto   = validate_or_default_node_int( node, "alto" , "tipoPrincesa", 40 );
    tipoPrincesa.velocidad   = validate_or_default_node_int( node, "velocidad" , "tipoPrincesa", 200 );
    tipoPrincesa.salto  = validate_or_default_node_int( node, "salto", "tipoPrincesa", 0 );
    
    if ( node.Type() == YAML::NodeType::Map ){
        if( (parsed = node.FindValue("animaciones")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> tipoPrincesa.animaciones;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoPrincesa no es del tipo correcto", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoPrincesa no existe", 2 );
        }
    } else {
        LOGUEAR( "YAML::WARNING! clave: 'animaciones' en tipoPrincesa no existe", 2 );
    }
}

void operator >> (const YAML::Node& node, Juego& juego) {
    const YAML::Node *parsed;
    const YAML::Node *empty;

    if ( node.Type() == YAML::NodeType::Map ){

        if( (parsed = node.FindValue("conexion")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.conexion;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'conexion' no es valida", 2 );
                *empty >> juego.conexion;
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'conexion' no existe", 2 );
            *empty >> juego.conexion;
        }

        if( (parsed = node.FindValue("pantalla")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.pantalla;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'pantalla' no es valida", 2 );
                *empty >> juego.pantalla;
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'pantalla' no existe", 2 );
            *empty >> juego.pantalla;
        }

        if( (parsed = node.FindValue("parametros")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.parametros;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'parametros' no es valida", 2 );
                *empty >> juego.parametros;
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'parametros' no existe", 2 );
            *empty >> juego.parametros;
        }

        /*
        if( (parsed = node.FindValue("nivel")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.nivel;
            } else {
                //TODO: poner valores por defecto para los valores de nivel
                LOGUEAR( "YAML::WARNING! clave: 'nivel' no es valida", 2 );
            }
        } else {
            //TODO: poner valores por defecto para los valores de nivel
            LOGUEAR( "YAML::WARNING! clave: 'nivel' no existe", 2 );
        }
          */
        if( (parsed = node.FindValue("niveles")) ) {
        	if ( (*parsed).Type() == YAML::NodeType::Map ){
        		*parsed >> juego.niveles;
            } else {
                //TODO: poner valores por defecto para los valores de nivel
                LOGUEAR( "YAML::WARNING! clave: 'niveles' no es valida", 2 );
            }
        } else {
            //TODO: poner valores por defecto para los valores de nivel
            LOGUEAR( "YAML::WARNING! clave: 'niveles' no existe", 2 );
        }

/*        if( (parsed = node.FindValue("texturas")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.texturas;
            } else {
                //TODO: poner valores por defecto para los valores de texturas
                LOGUEAR( "YAML::WARNING! clave: 'texturas' no es valida", 2 );
            }
        } else {
            //TODO: poner valores por defecto para los valores de texturas
            LOGUEAR( "YAML::WARNING! clave: 'texturas' no existe", 2 );
        }
*/
        /*
        if( (parsed = node.FindValue("sonidos")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.sonidos;
            } else {
                //TODO: poner valores por defecto para los valores de sonidos
                LOGUEAR( "YAML::WARNING! clave: 'sonidos' no es valida", 2 );
            }
        } else {
            //TODO: poner valores por defecto para los valores de sonidos
            LOGUEAR( "YAML::WARNING! clave: 'sonidos' no existe", 2 );
        }
  */

        if( (parsed = node.FindValue("templates")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.templates;
            } else {
                //TODO: poner valores por defecto para los valores de templates
                LOGUEAR( "YAML::WARNING! clave: 'templates' no es valida", 2 );
            }
        } else {
            //TODO: poner valores por defecto para los valores de templates
            LOGUEAR( "YAML::WARNING! clave: 'templates' no existe", 2 );
        }
/*
        if( (parsed = node.FindValue("imagenes")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
                *parsed >> juego.imagenes;
            } else {
                //TODO: poner valores por defecto para los valores de templates
                LOGUEAR( "YAML::WARNING! clave: 'imagenes' no es valida", 2 );
            }
        } else {
            //TODO: poner valores por defecto para los valores de templates
            LOGUEAR( "YAML::WARNING! clave: 'imagenes' no existe", 2 );
        }
*/
        if( (parsed = node.FindValue("tiposPersonaje")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
            	*parsed >> juego.tiposPersonaje;
            } else {
                //TODO: poner valores por defecto para los valores de tiposPersonaje
                LOGUEAR( "YAML::WARNING! clave: 'tiposPersonaje' no es valida", 2 );
            }
        } else {
            //TODO: poner valores por defecto para los valores de tiposPersonaje
            LOGUEAR( "YAML::WARNING! clave: 'tiposPersonaje' no existe", 2 );
        }

        if( (parsed = node.FindValue("tiposBonus")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
            	*parsed >> juego.tiposBonus;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'tiposBonus' no es valida", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'tiposBonus' no existe", 2 );
        }

        if( (parsed = node.FindValue("tiposEnemigo")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
            	*parsed >> juego.tiposEnemigo;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'tiposEnemigo' no es valida", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'tiposEnemigo' no existe", 2 );
        }

        if( (parsed = node.FindValue("tiposObstaculo")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
            	*parsed >> juego.tiposObstaculo;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'tiposObstaculo' no es valida", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'tiposObstaculo' no existe", 2 );
        }

        if( (parsed = node.FindValue("tipoPrincesa")) ) {
            if ( (*parsed).Type() == YAML::NodeType::Map ){
            	*parsed >> juego.tipoPrincesa;
            } else {
                LOGUEAR( "YAML::WARNING! clave: 'tipoPrincesa' no es valida", 2 );
            }
        } else {
            LOGUEAR( "YAML::WARNING! clave: 'tipoPrincesa' no existe", 2 );
            *empty >> juego.tipoPrincesa;
        }

    } else {
        LOGUEAR( "YAML::WARNING! clave: 'juego' no es valida", 2 );
    }
}

void print_parsed_yaml(Juego& juego)
{

    std::cout << "JUEGO:\n\n";
    std::cout << "pantalla:" << "\n";
    std::cout << "    ancho: " << juego.pantalla.ancho << "\n";
    std::cout << "    alto:  " << juego.pantalla.alto << "\n";
    std::cout << "parametros:" << "\n";
    std::cout << "    vel_personaje: " << juego.parametros.vel_personaje << "\n";
    std::cout << "    margen_scroll: " << juego.parametros.margen_scroll << "\n";

//    std::cout << "texturas: " << juego.texturas.size() << "\n";

/*    for(unsigned i=0;i<juego.texturas.size();i++) {
        std::cout << "    nombre" << i << ": " << juego.texturas[i].nombre << "\n";
        std::cout << "    archivo" << i << ": " << juego.texturas[i].archivo << "\n";
    }

    std::cout << "nivel:" << "\n";
    std::cout << "    ancho: " << juego.nivel.ancho << "\n";
    std::cout << "    alto:  " << juego.nivel.alto << "\n";
    std::cout << "    personajes: " << juego.nivel.personajes.size() << "\n";

    for(unsigned i=0;i<juego.nivel.personajes.size();i++) {
    std::cout << "        tipo" << i << ": " << juego.nivel.personajes[i].tipo << "\n";
    std::cout << "        x" << i << ": " << juego.nivel.personajes[i].x << "\n";
    std::cout << "        y" << i << ": " << juego.nivel.personajes[i].y << "\n";
    }

    std::cout << "    plataformas: " << juego.nivel.plataformas.size() << "\n";

    for(unsigned i=0;i<juego.nivel.plataformas.size();i++) {
    std::cout << "        textura" << i << ": " << juego.nivel.plataformas[i].textura << "\n";
    std::cout << "        x" << i << ": " << juego.nivel.plataformas[i].x << "\n";
    std::cout << "        y" << i << ": " << juego.nivel.plataformas[i].y << "\n";
    std::cout << "        ancho" << i << ": " << juego.nivel.plataformas[i].ancho << "\n";
    std::cout << "        alto" << i << ": " << juego.nivel.plataformas[i].alto << "\n";
    }

    std::cout << "    escaleras: " << juego.nivel.escaleras.size() << "\n";

    for(unsigned i=0;i<juego.nivel.escaleras.size();i++) {
    std::cout << "        textura" << i << ": " << juego.nivel.escaleras[i].textura << "\n";
    std::cout << "        x" << i << ": " << juego.nivel.escaleras[i].x << "\n";
    std::cout << "        y" << i << ": " << juego.nivel.escaleras[i].y << "\n";
    std::cout << "        ancho" << i << ": " << juego.nivel.escaleras[i].ancho << "\n";
    std::cout << "        alto" << i << ": " << juego.nivel.escaleras[i].alto << "\n";
    }
      */
    std::cout << "tiposPersonaje: " << juego.tiposPersonaje.size() << "\n";

    for(unsigned i=0;i<juego.tiposPersonaje.size();i++) {
        std::cout << "    tipo" << i << ": " << juego.tiposPersonaje[i].tipo << "\n";
        std::cout << "    ancho" << i << ": " << juego.tiposPersonaje[i].ancho << "\n";
        std::cout << "    alto" << i << ": " << juego.tiposPersonaje[i].alto << "\n";
        std::cout << "    velocidad" << i << ": " << juego.tiposPersonaje[i].velocidad << "\n";
        std::cout << "    salto" << i << ": " << juego.tiposPersonaje[i].salto << "\n";
        std::cout << "    animaciones:\n";

    for(unsigned j=0;j<juego.tiposPersonaje[i].animaciones.size();j++) {
        std::cout << "        descripcion" << i << "." << j << ": " << juego.tiposPersonaje[i].animaciones[j].descripcion << "\n";
        std::cout << "        periodo" << i << "." << j << ": " << juego.tiposPersonaje[i].animaciones[j].periodo << "\n";
        //std::cout << "    archivo" << i << ": " << juego.texturas[i].archivo << "\n";
    }
        //std::cout << "    archivo" << i << ": " << juego.texturas[i].archivo << "\n";
    }
}

std::vector<std::string> parser_lista_niveles( Juego& juego ) {
    std::vector<std::string> ret;
    int i;
    for (i = 0; i < juego.niveles.size(); i++) {
        ret.push_back( juego.niveles[i].nombre );
    }
    return ret;
}

void parsear( std::string filename , Juego& juego )
{
    std::ifstream fin( filename.c_str() );
    bool valido = fin;

    if (valido) {
        LOGUEAR("El archivo yaml "+filename+" especificado fue abierto correctamente.", 1);
		
        YAML::Parser parser(fin);
        YAML::Node doc;
        const YAML::Node *parsed;
		
        try {
            parser.GetNextDocument(doc);
        } catch(YAML::ParserException& e) {
            LOGUEAR("El archivo yaml "+filename+" especificado esta mal formado, usando el default.", 1);
            valido = false;
        }
        
        if (valido)
            try {
                parsed = doc.FindValue("juego");
                *parsed >> juego;
            } catch(YAML::BadDereference& e) {
                LOGUEAR( "YAML::WARNING! clave: 'juego' no existe.", 2 );
                LOGUEAR("Se utiliza el yaml default", 2);
                valido = false;
            }
    }
    
    if (!valido) {
		
        if (!fin) {
            if(filename.size() > 0)
                LOGUEAR("El archivo "+filename+" no existe. Se reemplaza por el default.", 2);
            else
                LOGUEAR("Se utiliza el archivo yaml default.", 1);
        }

        std::ifstream def_yaml( DEFAULT_YAML );	
		
        if (!def_yaml) {
            LOGUEAR("El archivo default del yaml no existe.", 3);
            exit(1);
        }
        else
            LOGUEAR("El archivo yaml default fue abierto correctamente.", 1);

        YAML::Parser default_parser(def_yaml);
        YAML::Node doc;
        const YAML::Node *parsed;

        try {
           default_parser.GetNextDocument(doc);
        } catch(YAML::ParserException& e) {
            LOGUEAR("El archivo yaml default esta mal formado. Fin del programa.", 3);
            exit(0);
        }

        try {
            parsed = doc.FindValue("juego");
            *parsed >> juego;
        } catch(YAML::BadDereference& e) {
            //TODO: TOMAR LOS VALORES POR DEFAULT DE JUEGO DEL DEFAUL.YAML
            LOGUEAR( "YAML::WARNING! clave: 'juego' no existe.", 2 );
            LOGUEAR("Yaml default erroneo. Fin del programa.", 3);
            exit(0);
        }
    }
}

